<?php

declare (strict_types = 1);

namespace App\Service\Organziation;

use App\Constants\ErrorCode;
use App\Dao\AuthAdminLogDao;
use App\Dao\AuthEmployeeDao;
use App\Dao\AuthOrganizationDao;
use App\Dao\AuthProjectDao;
use App\Dao\AuthProjectEmployeeDao;
use App\Dao\AuthProjectOrganizationDao;
use App\Exception\BusinessException;
use App\Model\AuthEmployee;
use App\Model\AuthProject;
use App\Model\AuthProjectEmployee;
use App\Service\Auth\ModuleService;
use App\Utils\ApiUtils;
use App\Utils\Redis;
use Hyperf\DbConnection\Db;
use Hyperf\Utils\Codec\Json;

class EmployeeService
{
    /**
     * 查询用户列表信息
     *
     * @Author czm
     * @DateTime 2020-09-30
     * @param array $params
     * @return void
     */
    function list(array $params) {
        if (isset($params['list_type']) && $params['list_type'] == 1) {
            $data = make(AuthEmployeeDao::class)->getByWhereTrait([['company_id', "=", $params['company_id']], ['entry_status', "=", AuthEmployee::ENTRY_STATUS_ING]], ['id', 'name'])->toArray();
        } else if (isset($params['list_type']) && $params['list_type'] == 2) {
            $ids = explode(",", $params['employee_ids']);
            $data = make(AuthEmployeeDao::class)->getWhereInKeyTrait('id', $ids, ['id', 'name']);
        } else {
            list($data, $count) = make(AuthEmployeeDao::class)->getWithRselevance($params, $params['page'], $params['pageSize']);
        }
        return ApiUtils::send(ErrorCode::SUCCESS, '操作成功', $data, $count ?? 1);
    }

    /**
     * 新建员工
     *
     * @Author czm
     * @DateTime 2020-10-01
     * @param array $params
     * @return void
     */
    public function addEmployee(array $params)
    {
        //验证员工名称是否存在
        $map = [
            ['name', '=', $params['name']],
            ['company_id', '=', $params['company_id']],
        ];
        if (make(AuthEmployeeDao::class)->existsByWhereTrait($map)) {
            throw new BusinessException(ErrorCode::ERR_BUESSUS, '公司下存在相同名称');
        }
        //验证工号是存在
        $map = [
            ['job_number', '=', $params['job_number']],
            ['company_id', '=', $params['company_id']],
        ];
        if (make(AuthEmployeeDao::class)->existsByWhereTrait($map)) {
            throw new BusinessException(ErrorCode::ERR_BUESSUS, '公司下存在相同工号');
        }

        //验证账号是否存在
        $map = [
            ['account', '=', $params['account']],
        ];
        if (make(AuthEmployeeDao::class)->existsByWhereTrait($map)) {
            throw new BusinessException(ErrorCode::ERR_BUESSUS, '该账号系统已存在');
        }
        //密码加密存储
        $params['password'] = ApiUtils::aesEnPassword($params['password']);
        //如果是不是全部则记录项目关联
        Db::beginTransaction();
        try {
            $employee = make(AuthEmployeeDao::class)->createTrait($params);
            $params['employee_id'] = $employee['id'];
            if ($params['partake_project'] == AuthEmployee::PARTAKE_PROJECT_PART && $params['join_project_id']) {
                $join_project_id = explode(",", $params['join_project_id']);
                $this->bindProject($join_project_id, $params);

            } else if ($params['partake_project'] == AuthEmployee::PARTAKE_PROJECT_ALL) {
                $join_project_id = array_column(make(AuthProjectDao::class)->searchAll([['company_id', '=', $params['company_id']], ['is_del', '=', 1], ['status', '=', AuthProject::IS_STATUS]], ['id']), 'id');
                $this->bindProject($join_project_id, $params);
            }
            //查看项目
            if ($params['check_project'] == AuthEmployee::CHECK_PROJECT_PART && $params['show_project_id']) {
                $show_project_id = explode(",", $params['show_project_id']);
            } else if ($params['check_project'] == AuthEmployee::CHECK_PROJECT_ALL) {
                $show_project_id = array_column(make(AuthProjectDao::class)->searchAll([['company_id', '=', $params['company_id']], ['is_del', '=', 1], ['status', '=', AuthProject::IS_STATUS]], ['id']), 'id');
            } else {
                $show_project_id = [];
            }
            foreach ($show_project_id as $val) {
                make(AuthProjectEmployeeDao::class)->add([
                    'employee_id' => $employee->id,
                    'project_id' => $val,
                    'type' => AuthProjectEmployee::SHOW_TYPE,
                    'company_id' => $params['company_id'],
                    'add_time' => time(),
                    'update_time' => time(),
                ]);
            }
            make(AuthAdminLogDao::class)->addLog('新增员工' . json_encode($params, JSON_UNESCAPED_UNICODE));
            Db::commit();
        } catch (\Throwable $t) {
            Db::rollBack();
            throw new BusinessException(ErrorCode::ERR_BUESSUS, '网络异常 数据写入失败' . config('web.err_msg_splite') . $t->getMessage());
        }
        return ApiUtils::send(ErrorCode::SUCCESS, "操作成功");
    }

    /**
     * 编辑员工
     *
     * @Author czm
     * @DateTime 2020-10-01
     * @param array $params
     * @return void
     */
    public function editEmployee(array $params)
    {
        //验证员工名称是否存在
        $map = [
            ['name', '=', $params['name']],
            ['company_id', '=', $params['company_id']],
            ['id', '!=', $params['employee_id']],
        ];
        if (make(AuthEmployeeDao::class)->existsByWhereTrait($map)) {
            throw new BusinessException(ErrorCode::ERR_BUESSUS, '公司下存在相同名称');
        }

        //验证工号是存在
        $map = [
            ['job_number', '=', $params['job_number']],
            ['company_id', '=', $params['company_id']],
            ['id', '!=', $params['employee_id']],

        ];
        if (make(AuthEmployeeDao::class)->existsByWhereTrait($map)) {
            throw new BusinessException(ErrorCode::ERR_BUESSUS, '公司下存在相同工号');
        }

        //验证账号是否存在
        $map = [
            ['account', '=', $params['account']],
            ['id', '!=', $params['employee_id']],
        ];
        if (make(AuthEmployeeDao::class)->existsByWhereTrait($map)) {
            throw new BusinessException(ErrorCode::ERR_BUESSUS, '该账号系统已存在');
        }
        //密码加密存储
        $params['password'] = ApiUtils::aesEnPassword($params['password']);
        //如果是不是全部则记录项目关联
        Db::beginTransaction();
        try {

            $params['id'] = $params['employee_id'];
            $logInfo = make(AuthEmployeeDao::class)->findTrait($params['id'])->toJson(JSON_UNESCAPED_UNICODE);
            make(AuthEmployeeDao::class)->updateByIdTrait($params);
            if ($params['partake_project'] == AuthEmployee::PARTAKE_PROJECT_PART && $params['join_project_id']) {
                $join_project_id = explode(",", $params['join_project_id']);
                //排除负责人关联项目信息
                $organiztion_ids = make(AuthOrganizationDao::class)->getByWhereTrait(['employee_id' => $params['employee_id']])->pluck('id')->toArray();
                if ($organiztion_ids) {
                    $project_ids = make(AuthProjectOrganizationDao::class)->getByWhereIn([], $organiztion_ids)->pluck('project_id')->toArray();
                    $join_project_id = array_merge($project_ids, $join_project_id);

                }
                make(AuthProjectEmployeeDao::class)->delNotInIds($join_project_id, [
                    ['type', '=', AuthProjectEmployee::JOIN_TYPE],
                    ['employee_id', '=', $params['employee_id']]]
                );
                $this->bindProject($join_project_id, $params);
            } else if ($params['partake_project'] == AuthEmployee::PARTAKE_PROJECT_ALL) {
                $join_project_id = array_column(make(AuthProjectDao::class)->searchAll([['company_id', '=', $params['company_id']], ['is_del', '=', 1], ['status', '=', AuthProject::IS_STATUS]], ['id']), 'id');
                $this->bindProject($join_project_id, $params);
            }
            //查看项目
            if ($params['check_project'] == AuthEmployee::CHECK_PROJECT_PART && $params['show_project_id']) {
                $show_project_id = explode(",", $params['show_project_id']);
            } else if ($params['check_project'] == AuthEmployee::CHECK_PROJECT_ALL) {
                $show_project_id = array_column(make(AuthProjectDao::class)->searchAll([['company_id', '=', $params['company_id']], ['is_del', '=', 1], ['status', '=', AuthProject::IS_STATUS]], ['id']), 'id');
            } else {
                $show_project_id = [];
            }
            make(AuthProjectEmployeeDao::class)->delNotInIds($show_project_id, [
                ['type', '=', AuthProjectEmployee::SHOW_TYPE],
                ['employee_id', '=', $params['employee_id']]]
            );
            foreach ($show_project_id as $val) {
                make(AuthProjectEmployeeDao::class)->firstOrCreate([
                    'employee_id' => $params['employee_id'],
                    'project_id' => $val,
                    'type' => AuthProjectEmployee::SHOW_TYPE,
                    'add_time' => time(),
                    'update_time' => time(),
                    'is_del' => 1,
                ], [
                    'employee_id' => $params['employee_id'],
                    'project_id' => $val,
                    'type' => AuthProjectEmployee::SHOW_TYPE,
                    'company_id' => $params['company_id'],
                    'is_del' => 1,
                ]);
            }
            make(AuthAdminLogDao::class)->addLog('编辑员工' . json_encode($params, JSON_UNESCAPED_UNICODE) . "原数据 " . $logInfo);
            Db::commit();
            //更新redis缓存信息
            $this->userInfo(['employee_id' => $params['employee_id']]);
        } catch (\Throwable $t) {
            Db::rollBack();
            throw new BusinessException(ErrorCode::ERR_BUESSUS, '网络异常 数据写入失败' . config('web.err_msg_splite') . $t->getMessage());
        }
        return ApiUtils::send(ErrorCode::SUCCESS, "操作成功");
    }

    /**
     * 修改密码
     *
     * @Author czm
     * @DateTime 2020-09-29
     * @param array $params
     * @return void
     */
    public function editPassword(array $params)
    {
        $employee = make(AuthEmployeeDao::class)->findTrait($params['id']);
        if ($employee->password != ApiUtils::aesEnPassword($params['password'])) {
            throw new BusinessException(ErrorCode::ERR_BUESSUS, '旧密码错误');
        }
        //密码加密存储
        $params['password_confirmation'] = ApiUtils::aesEnPassword($params['password_confirmation']);
        $employee->password = $params['password_confirmation'];
        $employee->save();
        make(AuthAdminLogDao::class)->addLog('用户修改密码id: ' . $params['id']);
        return ApiUtils::send(ErrorCode::SUCCESS, "操作成功");
    }

    /**
     * 账号密码登陆
     *
     * @Author czm
     * @DateTime 2020-09-29
     * @param array $params
     * @return void
     */
    public function login(array $params)
    {
        $employee = make(AuthEmployeeDao::class)->firstByWhereTrait(['account' => $params['account']]);

        if (empty($employee)) {
            throw new BusinessException(ErrorCode::ERR_BUESSUS, '账号不存在');
        }
        $key = AuthEmployee::REDIS_EMPLOYEE_LOGIN_LOCK . $params['account'];
        $lock = make(Redis::class)->get($key);

        if ($lock && $lock > AuthEmployee::REDIS_EMPLOYEE_LOGIN_LOCK_NUM) {
            throw new BusinessException(ErrorCode::ERR_BUESSUS, '账号验证失败次数超过上限 解锁时间24小时内');
        }

        if ($employee->password != ApiUtils::aesEnPassword($params['password'])) {
            !$lock && $lock = 0;
            make(Redis::class)->set($key, $lock + 1, ['EX' => 86400]);
            throw new BusinessException(ErrorCode::ERR_BUESSUS, '密码错误');
        }
        //所存在则删除锁
        $lock && make(Redis::class)->del($key);

        if ($employee->status != AuthEmployee::STATUS_NORMAL) {
            throw new BusinessException(ErrorCode::ERR_BUESSUS, '账号停用 请联系管理员');
        }
        $data = [
            'permission_cache_key' => make(ModuleService::class)->userHasModule(['employee_id' => $employee->id])['data']['cache_key'],
            'user_cache_key' => $this->userInfo(['employee_id' => $employee->id])['data']['cache_key'],
            'db' => env('REDIS_DB', 0),
        ];
        $employee->last_login_time = time();
        $employee->save();
        return ApiUtils::send(ErrorCode::SUCCESS, "操作成功", $data);
    }

    /**
     * 根据用户信息获取用户信息
     *
     * @Author czm
     * @DateTime 2020-10-10
     * @param array $params
     * @return void
     */
    public function userInfo(array $params)
    {
        $employee_id = $params['employee_id'];
        $employee = make(AuthEmployeeDao::class)->firstByWhereTrait(['id' => $employee_id]);
        $hasOrganization = $employee->hasOrganization;
        $hasDuty = $employee->hasDuty;
        if ($hasOrganization) {
            $organization_name = $hasOrganization->name;
        }
        if ($hasDuty) {
            $duty_name = $hasDuty->name;
        }
        $data = [
            'id' => $employee->id,
            'company_id' => $employee->company_id,
            'job_number' => $employee->job_number,
            'name' => $employee->name,
            'account' => $employee->account,
            'duty_id' => $employee->duty_id,
            'organization_id' => $employee->organization_id,
            'phone' => $employee->phone,
            'duty_name' => $duty_name,
            'organization_name' => $organization_name,
            'sex' => $employee->sex,
            'entry_status' => $employee->entry_status,
            'entry_time' => $employee->entry_status,
        ];
        //前缀加id
        $key = config('web.user_cache_key') . $employee->id;
        make(redis::class)->set($key, Json::encode($data), ['EX' => 86400 * 2]);
        return ApiUtils::send(ErrorCode::SUCCESS, "操作成功", ['cache_key' => $key, 'db' => env('REDIS_DB', 0)]);
    }
    /**
     * 建立部门与负责人的项目关联
     *
     * @Author czm
     * @DateTime 2020-10-16
     * @param [type] $join_project_id
     * @param [type] $params
     * @return void
     */
    public function bindProject($join_project_id, $params)
    {
        //获取关联的部门
        $findParentIdsWithPrincipal = make(AuthOrganizationDao::class)->findParentIdsWithPrincipal($params['organization_id']);
        foreach ($join_project_id as $val) {
            //编辑或者新增员工关联项目
            make(AuthProjectEmployeeDao::class)->firstOrCreate(
                [
                    'employee_id' => $params['employee_id'],
                    'project_id' => $val,
                    'type' => AuthProjectEmployee::JOIN_TYPE,
                    'company_id' => $params['company_id'],
                    'add_time' => time(),
                    'update_time' => time(),
                    'organization_id' => 0,
                    'is_del' => 1,
                ], [
                    'employee_id' => $params['employee_id'],
                    'project_id' => $val,
                    'type' => AuthProjectEmployee::JOIN_TYPE,
                    'company_id' => $params['company_id'],
                    'organization_id' => 0,
                    'is_del' => 1,
                ]);
            //追最顶级部门与负责人的项目关联
            $lock = true;
            $principals = [];
            $organization_ids = make(AuthProjectOrganizationDao::class)->searchAll([
                ['company_id', '=', $params['company_id']],
                ['project_id', '=', $val],
            ], ['organization_id']);
            $organization_ids = array_column($organization_ids, 'organization_id');
            foreach ($findParentIdsWithPrincipal as $k => $v) {
                if (in_array($k, $organization_ids)) {
                    $lock = false;
                    break;
                } else {
                    $principals[$k] = $v;
                }

            }
            //如果顶级公司不存在则记录绑定当前部门项目关联
            if ($lock) {
                make(AuthProjectOrganizationDao::class)->firstOrCreate([
                    'organization_id' => $params['organization_id'],
                    'project_id' => $val,
                    'company_id' => $params['company_id'],
                    'add_time' => time(),
                ], [
                    'organization_id' => $params['organization_id'],
                    'project_id' => $val,
                    'company_id' => $params['company_id'],
                ]);
                //去除所有下级部门的项目部门关联
                make(AuthProjectOrganizationDao::class)->delChildProject($params['organization_id'], $val);
                //部门负责人绑定
                ($findParentIdsWithPrincipal[$params['organization_id']] ?? "") && make(AuthProjectEmployeeDao::class)->firstOrCreate([
                    'employee_id' => $findParentIdsWithPrincipal[$params['organization_id']],
                    'project_id' => $val,
                    'company_id' => $params['company_id'],
                    'type' => AuthProjectEmployee::JOIN_TYPE,
                    'organization_id' => $params['organization_id'],
                    'add_time' => time(),
                    'update_time' => time(),
                ], [
                    'employee_id' => $findParentIdsWithPrincipal[$params['organization_id']],
                    'project_id' => $val,
                    'company_id' => $params['company_id'],
                    'type' => AuthProjectEmployee::JOIN_TYPE,
                    'organization_id' => $params['organization_id'],
                ]);
            } else {
                foreach ($principals as $k => $v) {
                    //链路上负责人绑定
                    $v && make(AuthProjectEmployeeDao::class)->firstOrCreate([
                        'employee_id' => $v,
                        'project_id' => $val,
                        'company_id' => $params['company_id'],
                        'type' => AuthProjectEmployee::JOIN_TYPE,
                        'organization_id' => $k,
                        'add_time' => time(),
                        'update_time' => time(),
                    ], [
                        'employee_id' => $v,
                        'project_id' => $val,
                        'company_id' => $params['company_id'],
                        'type' => AuthProjectEmployee::JOIN_TYPE,
                        'organization_id' => $k,
                    ]);
                }

            }

        }}

    /**
     * 修改员工状态
     *
     * @Author czm
     * @DateTime 2020-10-21
     * @param array $params
     * @return void
     */
    public function editEmployeeStauts(array $params)
    {
        $employee = make(AuthEmployeeDao::class)->findTrait($params['employee_id']);
        if (isset($params['status']) && $params['status']) {
            $employee->status = $params['status'];
        }
        if (isset($params['admin_status']) && $params['admin_status']) {
            $employee->admin_status = $params['admin_status'];
        }
        $employee->save();
        make(AuthAdminLogDao::class)->addLog('用户修改员工状态id: ' . $params['employee_id'] . "内容 " . json_encode($params, JSON_UNESCAPED_UNICODE));
        $this->userInfo(['employee_id' => $params['employee_id']]);
        return ApiUtils::send(ErrorCode::SUCCESS, "操作成功");
    }

}
